/**
 * 发布订阅模式(Publish-subscribe model)
 * 一种 对象 间一对多的依赖关系，当一个对象的状态发送改变时，所有依赖于它的对象都将得到状态改变的通知
 * 
 * 作用：
 * 1.广泛应用于异步编程中(替代了传递回调函数)
 * 2.对象之间松散耦合的编写代码
 * 
 * 实现发布订阅
 */


let company = {};   // 定义一个公司对象
company.list = [];  // 缓存回调函数

company.on = function(key, fn){  // 去订阅事件
  if(!this.list[key]){ // 如果对象中没有key值，没订阅过，创建一个缓存
    this.list[key] = [];
  }
  this.list[key].push(fn);
};

company.emit = function(){  // 发布事件
  let key = [].shift.call(arguments)
      fns = this.list[key];
  if(!fns || fns.length === 0){  // 缓存列表中没有函数就返回false
    return false;
  }
  fns.forEach(item => {
    item.apply(this, arguments);
  });
};

// 测试用例
company.on('job', function(position, salary){
  console.log('你的职位是： ' + position);
  console.log('期望薪水： ' + salary);
});

company.on('other', function(skill, hobby){
  console.log('你的技能： ' + skill);
  console.log('爱好：' + hobby);
});

company.emit('job' , '财务', 10000);
company.emit('other', '数钱', '健身');


/**
 *  通用写法
 *  思路：
 *  创建一个对象(缓存列表)
 *  on方法用来把回调函数fn都加到缓存列表中
 *  emit方法取到arguments里第一个当做key，根据key值去执行对应缓存列表中的函数
 *  remove方法可以根据key值取消订阅
 */
let event = {
  list: {},
  on(key, fn){
    if(key, fn){
      if(!this.list[key]){
        this.list[key] = [];
      }
      this.list[key].push(fn);
    }
  },
  emit(){
    let key = [].shift.call(arguments),
        fns = this.list[key];
    
    if(!fns || fns === 0){
      return false;
    }
    fns.forEach(fn => {
      fn.apply(this, arguments);
    });
  },
  remove(key, fn){
    let fns = this.list[key];
    if(!fns){
      return false;
    }
    if (!fn) {
      fns && (fns.length = 0);
    } else {
      fns.forEach((cb, i) => {
        if (cb === fn) {
          fns.splice(i, 1);
        }
      });
    }
  }
}


/**
 * 运用实例：
 * 1.在文章列表页中插入广告，与分页一起使用的时候。
 * 2.打点，记录用户行为，根据上文页面内容，"猜你喜欢"这个部分。
 * 3.Nodejs的EventEmitter
 */


 